/*

This file is part of roomyak.

Copyright (C) 2008 Pixecur Technologies Incorporated (Esotera).
Visit Esotera at http://www.esoteras3.com
 
roomyak is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
roomyak is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with roomyak; see the file COPYING.  If not, write to 
Pixecur Technologies, 213-31 Peet Street, St. John's, NL, A1B 3W8. 
 
Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
 
*/

package com.datasentinel.util.data;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

/**
 * This class does not grow it's buffer but throws 
 * OutOfBoundsException if there is not enough space in the
 * internal buffer to store the written bytes. 
 * 
 * @author Areg Beketovski
 */
public class FixedSizeByteArrayOutputStream extends ByteArrayOutputStream
{

	private int offset;
	private final int length;

	public FixedSizeByteArrayOutputStream(byte[] buffer)
	{
		this(buffer, 0, buffer.length);
	}

	public FixedSizeByteArrayOutputStream(byte[] buffer, int offset, int length)
	{
		this.buf = buffer;
		this.offset = offset;
		this.length = length;

		this.count = offset;
	}

	@Override
	public synchronized void reset()
	{
		this.count = offset;
	}

	public synchronized void reset(int offset)
	{
		this.offset = offset;
		reset();
	}

	public synchronized void write(int b)
	{
		int newcount = count + 1;
		if (newcount > length)
		{
			throw new OutOfBoundsException(length - count, 1);
		}
		buf[count] = (byte)b;
		count = newcount;
	}

	/**
	 * Writes <code>len</code> bytes from the specified byte array 
	 * starting at offset <code>off</code> to this byte array output stream.
	 *
	 * @param   b     the data.
	 * @param   off   the start offset in the data.
	 * @param   len   the number of bytes to write.
	 */
	public synchronized void write(byte b[], int off, int len)
	{
		if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0))
		{
			throw new IndexOutOfBoundsException();
		}
		else if (len == 0)
		{
			return;
		}
		int newcount = count + len;
		if (newcount > (length + offset))
		{
			throw new OutOfBoundsException(length - count, len);
		}
		System.arraycopy(b, off, buf, count, len);
		count = newcount;
	}


	@Override
	public synchronized void writeTo(OutputStream out) throws IOException
	{
		out.write(buf, offset, count - offset);
	}

	@Override
	public synchronized byte toByteArray()[]
	{
		return Arrays.copyOfRange(buf, offset, count - offset);
	}

	@Override
	public synchronized int size()
	{
		return count - offset;
	}

	public synchronized String toString()
	{
		return new String(buf, offset, count - offset);
	}

	public synchronized String toString(String charsetName) throws UnsupportedEncodingException
	{
		return new String(buf, offset, count - offset, charsetName);
	}
	
}
